package org.linuxgears.BouncingBall.mover.strategy;

import java.awt.Point;

import org.linuxgears.BouncingBall.tools.BallTools;

public class ControlledMovingStrategy implements ProgressiveMovingStrategy {
    public static final double DEFAULT_BALL_VELOCITY = 4;
	private enum State { STOPPED, TARGET, MOVING, STOPPING };
	
	private State state;
	private Point position;
	
	private double distanceToTarget;
	private double distancePassed;
	private double initialVelocityValue;
	private double absoluteVelocityValue;
	private double distanceX;
	private double distanceY;
	
	private Point startingPoint;
	private Point targetPoint;

	
	public ControlledMovingStrategy() {
		position = new Point();
		state = State.STOPPED;
		initialVelocityValue = DEFAULT_BALL_VELOCITY;		
	}

	public Point getTargetPoint() {
		return targetPoint;
	}
	
	@Override
	public void move() {
		if (state != State.MOVING) return;

		distancePassed += absoluteVelocityValue;
		if (distancePassed > distanceToTarget) {
			// we've reached the target point in this micro-move
			position.x = targetPoint.x;
			position.y = targetPoint.y;
			
			state = State.STOPPING;
			stopMoving();
			
			return;
		};
		
		// calculate new position, based on distance passed, it's a hack :)
		Point delta = BallTools.expandVector(startingPoint, targetPoint, distancePassed);
		
		position.x = startingPoint.x + delta.x;
		position.y = startingPoint.y + delta.y;
	}

	public void setTargetPoint(Point target) {
		if (null == target) return; // fuck it
		
		this.targetPoint = target;
		state = State.TARGET;
		
		startMoving();
	}
	
	public void startMoving() {
		if (state != State.TARGET) return;		// no target yet
		
		// calculate velocity based on the default ball velocity
		// and target position
		
		// speedFactor is distance to go divided by distance
		// moved in one tick, IOW "velocity"
		distanceX = targetPoint.x - position.x;
		distanceY = targetPoint.y - position.y;
		startingPoint = (Point) position.clone();

		distanceToTarget = Math.sqrt(Math.pow(distanceX, 2)
				+ Math.pow(distanceY, 2));

		distancePassed = 0.0;
		
		absoluteVelocityValue = initialVelocityValue;

		state = State.MOVING;		
	}
	
	public void stopMoving() {
		if (state != State.STOPPING) return;
		
		initialVelocityValue = absoluteVelocityValue;
		
		this.targetPoint = null;
		state = State.STOPPED;
	}
	

	@Override
	public Point getPosition() {
		return position;
	}

	@Override
	public Point getVelocity() {
		if (state == State.MOVING) {
			return BallTools.expandVector(startingPoint, targetPoint, absoluteVelocityValue);
		} else  {
			return new Point();
		}
	}

	@Override
	public void setVelocity(Point velocity) {
		absoluteVelocityValue = BallTools.distance(new Point(0, 0), velocity);
	}

	@Override
	public void setPosition(Point position) {
		this.position = position;
		// need to recalculate velocity vector;
		setTargetPoint(targetPoint);
		
	}	
}
